﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure;
using Microsoft.Samples.WindowsAzure.ServiceManagement;
using System.ComponentModel;
using System.Diagnostics;
using System.Data.Objects;
using System.Data.Objects.DataClasses;


namespace WAPA.Framework
{
    /// <summary>
    /// Manages scenarios related to the Windows Azure performance analysis.
    /// </summary>
    public sealed class ScenarioManager
    {
        public delegate void ScenarioCompletedHandler();
        public event ScenarioCompletedHandler TaskCompleted;

        public static void AddScenario(Scenario scenario)
        {
            if (Scenarios == null)
                Scenarios = new List<Scenario>();

            Scenarios.Add(scenario);
        }
        /// <summary>
        /// Test setup
        /// </summary>
        public static void ExecuteScenario()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += delegate(object s, DoWorkEventArgs args)
            {
                Debug.WriteLine("Executing tasks ");
                foreach (Scenario t in Scenarios)
                {
                    t.Execute();
                }

                //We clear the tasklist when everything is completed.
                Scenarios.Clear();
            };


            worker.RunWorkerAsync();
        }

        public static List<Scenario> Scenarios;

        /// <summary>
        /// Adds a certificate to a hosted service.
        /// </summary>
        /// <param name="serviceName"></param>
        public static void AddCertificateToService(string serviceName)
        {
            //Certificateformats: cert|pfx|pkcs12|pkcs7
            CertificateFile certificateFile = new CertificateFile
            {
                Password = ManagementContext.CertificatePrivateKeyPassword,
                CertificateFormat = "pfx",
                Data = ManagementContext.certificate.GetRawCertDataString()
            };

            CloudServiceManager.AddCertificateToService(certificateFile, serviceName);
        }


        public static string DeployPiCalculatorPackage(HostedService hostedService, string deploymentSlot = "staging", string vmSize = "Small", int noInstances = 1)
        {
            //TODO:Use the an XMLDocument and XPath for this.
            string updatedConfigInstanceCount = ManagementContext.WorkerConfig.Replace("<Instances count=\"1\" />", "<Instances count=\"" + noInstances + "\" />");
            //We put the service label in config so we can link to this instance without the need to wait for
            //the deployment to collect the deploymentId. 
            //TODO:Remark: Instances from both staging and production slots will pick from the same queue!
            updatedConfigInstanceCount = updatedConfigInstanceCount.Replace("<Setting name=\"HostedServiceTag\" value=\"hostedservicetagplaceholder\" />", "<Setting name=\"HostedServiceTag\" value=\"" + hostedService.ServiceName + "\" />");

            if (noInstances < 1) noInstances = 1;

            if (noInstances > ManagementContext.AccountQuotaCores) noInstances = ManagementContext.AccountQuotaCores;

            //By naming convention we select the correct package for the VMSize requested
            //TODO: Finish the packageupdater
            string packageBlobName = ManagementContext.PackageFileName.Replace(".cspkg", vmSize + ".cspkg");

            CreateDeploymentInput createDeploymentInput = new CreateDeploymentInput
               {
                   Label = Guid.NewGuid().ToString(),
                   Name = hostedService.HostedServiceProperties.Label +"PiCalculator",
                   PackageUrl = new Uri("http://" + ManagementContext.StorageAccountName + ".blob.core.windows.net/" + ManagementContext.PackageContainerName + "/" + packageBlobName),
                   Configuration = updatedConfigInstanceCount,
                   StartDeployment = true,
                   TreatWarningsAsError = false
               };

            return CloudServiceManager.CreateDeployment(createDeploymentInput, hostedService.ServiceName, deploymentSlot);
        }

        /// <summary>
        /// Create a hosted service in a specified region
        /// </summary>
        /// <param name="regionName"></param>
        public static string CreateHostedServiceByRegionName(string regionName)
        {
            CreateHostedServiceInput createWEHostedServiceInput = new CreateHostedServiceInput()
            {
                ServiceName = Guid.NewGuid().ToString(),
                Label = regionName.Replace(" ", "") + "Service",
                Description = "Auto created by the WAPA tool.",
                Location = regionName
            };

            CloudServiceManager.CreateHostedService(createWEHostedServiceInput);

            return createWEHostedServiceInput.ServiceName;
        }

        /// <summary>
        /// Create an action for setting up the environment.
        /// </summary>
        /// <param name="locations"></param>
        public static void SetupTopology(LocationList locations)
        {
            ManagementContext.HostedServicesLastRefresh = DateTime.MinValue;
            SetupCloudTopologyAction setupCloudTopologyAction = new SetupCloudTopologyAction();

            setupCloudTopologyAction.Locations = locations;
            Scenario scenario = new Scenario();
            scenario.Actions.Add(setupCloudTopologyAction);

            ManagementContext.ActiveScenario = scenario;
            ScenarioManager.AddScenario(ManagementContext.ActiveScenario);

            var context = new WAPA.Data.WAPAModelContainer();

            //var scenarioRow = context.CreateEntityKey(<WAPA.Data.Scenario>();

            //scenarioRow.Description =  "Adding Hosted Services for " + locations.Count.ToString() + " services.";
            //scenarioRow.ResultQuery = "";
            //scenarioRow.Status = "Started";



            //context.Scenarios.AddObject(scenarioRow);
            //context.SaveChanges();

            ScenarioManager.ExecuteScenario();

            //var currentScenario = context.Scenarios.Where(e => e.Id == scenarioRow.Id);

        }

        public static void SendCalculationTasks(DeploymentList deployments, int precision, int repeatCount, int repeatInterval)
        {
            SendCalculationTasksAction sendCalculationTasksAction = new SendCalculationTasksAction();

            sendCalculationTasksAction.Deployments = deployments;
            sendCalculationTasksAction.NoMillionDigits = precision;
            sendCalculationTasksAction.RepeatCount = repeatCount;
            sendCalculationTasksAction.RepeatInterval = repeatInterval;
          

            Scenario scenario = new Scenario();
            scenario.Actions.Add(sendCalculationTasksAction);

            ManagementContext.ActiveScenario = scenario;
            ScenarioManager.AddScenario(scenario);

            ScenarioManager.ExecuteScenario();

        }

        public static void DeployCalculationServices(HostedServiceList hostedServices, DeploymentSlots deploymentSlot, VMSizes vmSize, int noInstances)
        {
            ManagementContext.HostedServicesLastRefresh = DateTime.MinValue;
            DeployCalculationServicesAction deployCalculationServicesAction = new DeployCalculationServicesAction();

            deployCalculationServicesAction.HostedServices = hostedServices;
            deployCalculationServicesAction.DeploymentSlot = deploymentSlot;
            deployCalculationServicesAction.VmSize = vmSize;
            deployCalculationServicesAction.NoInstances = noInstances;

            Scenario scenario = new Scenario();
            scenario.Actions.Add(deployCalculationServicesAction);

            ManagementContext.ActiveScenario = scenario;
            ScenarioManager.AddScenario(scenario);

            ScenarioManager.ExecuteScenario();
        }
    }
}
